//
// Created by luo on 2022-08-25.
//

#include "cpp.h"
#include <string.h>
#include <stdio.h>

//结构体类型,未分配储存单元
struct Date
{
    int month;
    int day;
    int year;
};

struct Student
{
    //类型名 + 成员列表名
    int num;
    char name[20];
    char sex;
    int age;
    float score;
    struct Date birthday; //成员birthday属于struct Date类型
    char addr[30];
}student3,student4;

struct Student_
{
    //类型名 + 成员列表名
    int num;
    char name[20];
    char sex;
    int age;
};

struct Person
{
    char name[20];
    int count; //得票数
}leader[3] = {"a",0,"b",0,"c",0};

void CppDemo::struct_demo()
{
   //允许自己建立由不同类型数据组合的组合型数据结构，为结构体
   /*
    * 定义结构体类型变量
    * */
   //1、先声明结构体类型，再定义该类型的变量
   struct Student student1,student2;
   //2、在声明类型的同时定义变量，不多用

   //3、不指定类型名而直接定义结构体类型变量

   //9.1.3结构体变量初始化
   //在定义变量的同时以{常量1，常量2，...}的顺序初始化
   //结构体变量名.成员名 引用其值 .成员运算符优先级最高
   student1.name[0] = 'lzp';
   student1.num = 202021724205;
   //层级关系，用.不断找到最后一级
    student1.birthday.year = 2000;
    student1.birthday.month = 11;
    student1.birthday.day = 13;
   //同类结构体变量可以相互赋值
   //结构体变量的地址主要作用于函数参数，传递结构体变量的地址

   //9.2 使用结构体数组
   //9.2.1 定义结构体数组
   /*
    * 1、struct 结构体名
    * {成员列表} 数组名[数组长度]
    *
    * 2、先声明结构体类型，再 结构体类型 数组名[数组长度]
    * 如 struct Person leader[3]
    * 结构体数组初始化
    * 如 struct Person leader[3] = {"a",0,"b",0,"c",0};
    * */

//   int i,j;
//   char leader_name[20];
//   for(i = 1; i <= 10;i++)
//   {
//       scanf("%s",leader_name);
//       for(j = 0; j<3; j++)
//       {
//           if(strcmp(leader_name,leader[j].name)==0)
//               leader[j].count++;
//       }
//   }
//   printf("\nResult:\n");
//   for(i = 0; i<3; i++)
//   {
//       printf("%5s:%d\n",leader[i].name,leader[i].count);
//   }

   /*
    * 选择排序法：
    * 外循环由i=0遍历到i<n-1(数组长度)，然后设置下标值变量k=i，内循环为j=i+1,遍历到j<n
    * 然后进行前后数据比较,若大/小则将当前下标j赋值给k，然后根据下标值做相应交换temp;
    * */

   //9.3 结构体指针
   //结构体指针:指向结构体变量的指针，
   //指向结构体对象的指针变量既可指向结构体变量，也可以指向结构体数组中的元素
   struct Student *p; //p可指向结构体变量，也可以指向结构体数组中的元素
   struct Student stu_1;
   p = &stu_1; //p指向stu_1
   stu_1.num = 10101;
   strcpy(stu_1.name,"Li Lin");
   stu_1.sex = 'M';
   stu_1.score = 89.5;
   printf("No:%d\nname:%s\nsex:%c\nscore:%5.1f\n",
          stu_1.num,stu_1.name,stu_1.sex,stu_1.score);
   //(*p)指向结构体变量,(*p).num表示指向的结构体变量中的成员num
   //*p.num等价于*(p.num)
   //(*p).num等价于p->num

   /*
    * p指向一个结构体变量stu，以下三种方法等价
    * stu.成员名
    * (*p).成员名
    * p->成员名
    * */
   printf("No:%d\nname:%s\nsex:%c\nscore:%5.1f\n",
           (*p).num,(*p).name,(*p).sex,(*p).score);
   printf("No:%d\nname:%s\nsex:%c\nscore:%5.1f\n",
           p->num,p->name,p->sex,p->score);

    //9.3.2 指向结构体数组的指针
    //可以用指针变量指向结构体数组的元素
    //类型名 + 成员列表名
   struct Student_ stu_2[2] = {
           {1,'a','M',10,},
           {2,'b','G',20,}
   };
   struct Student_ *pt;
   printf("No.  Name          sex age\n");
   for(pt=stu_2;pt<stu_2+2;pt++)
   {
       printf("%5d %-20s %2c %4d\n",pt->num,pt->name,pt->sex,pt->age);
   }

   //9.3.3用结构体变量和结构体变量的指针作函数参数
   return;
}

//初始化链表
struct LinkNode_ *Init_LinkList(void)
{
    //创建头结点
    //malloc时动态内存分配函数，用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址
    struct LinkNode_ *header = (struct LinkNode_ *)malloc(sizeof(struct LinkNode_));
    header->data = -1;
    header->next = NULL;

    //尾部指针
    struct LinkNode_ *pRear = header;

    int val = -1;
    while(true)
    {
        printf("please input a num:\n");
        scanf("%d",&val);
        if(val == -1)
        {
            break;
        }

        //先创建新节点
        struct LinkNode_ *newnode = (struct LinkNode_ *) malloc(sizeof(struct LinkNode_));
        newnode->data = val;
        newnode->next = NULL;

        //新节点插入到链表中
        pRear->next = newnode;

        //更新尾部指针指向
        pRear = newnode;
    }
    return header;
}

//在值为oldval后面插入一个新的数据newval
void InsertByValue_LinkList(struct LinkNode_ *header,int oldval,int newval)
{

}

//删除值为val的结点
void RemoveByValue_Linkist(struct LinkNode_ *header,int delValue)
{

}

//遍历链表
void Foreach_LinkList(struct LinkNode_ *header)
{
    if(NULL == header)
    {
        return;
    }

    //辅助指针变量
    struct LinkNode_ *pCurrent = header->next;
    while(pCurrent != NULL)
    {
        printf("%d ",pCurrent->data);
        pCurrent = pCurrent->next;
    }
}

//销毁链表
void Destroy_LinkList(struct LinkNode_ *header)
{

}

//清空链表
void Clear_LinkList(struct LinkNode_ *header)
{

}

//定义函数，此函数返回一个指向链表头的指针
int n;
struct Student__ *create(void)
{
    struct Student__ *head,*p1,*p2;
    n = 0;
    p1 = p2 = (struct Student__*) malloc(LEN);//开品新单元
    scanf("%ld,%f",&p1->num,&p2->score);
    head = NULL;
    while(p1->num!=0)
    {
        n+=1;
        if(n==1) head = p1;
        else p2->next = p1;
        p2 = p1;
        p1 = (struct Student__*) malloc(LEN);//开辟动态内存，把起始地址赋值给p1
        scanf("%ld,%f",&p1->num,&p1->score);//输入其他学生的学号和成绩
    }
    p2->next = NULL;//链表尾
    return (head);
};
void CppDemo::linklist_demo()
{
    //9.4 用指针处理链表
    /*
     * 链表，常见的数据结构，动态进行存储分配。
     * 数组存放数据，需先固定数组元素个数(长度)，容易浪费内存。
     * 链表根据需要而开辟内存单元，在内存中是非连续的，且查找效率相对于数据低，且多了指针域的内存开销
     * 链表在指定位置插入和删除数据不需要移动元素，只需要修改指针(前后)即可
     * */

    /*
     * 链表分为：
        静态链表、动态链表
        单向链表、双向链表、循环链表、单向循环链表、双向循环链表
        拿到链表第一个结点，即可获取整个链表
     * */

    /*
     * 链表(在内存中是非连续的)：
        1、"头指针"变量,head，存放一个地址，指向第一个元素
        2、链表中每个元素称为"结点"，包含两个部分：
            2-1、用户需要的实际数据；
            2-2、下一个结点的地址
        3、最后一个元素，"表尾"，地址部分存放一个"NULL"表示空地址，链表到此结束
     * */

    //使用链表，要找到其他元素必须先找到上一个元素，无头指针整个链表都无法访问
    //利用结构体来创建链表，内部包含各种数据变量以及地址变量
    struct Student_l
    {
        int num;
        float score;
        struct Student_l *next; //next是指针变量，指向结构体变量
    };

    //9.4.2 建立简单的静态链表
    //静态链表：所有节点均在程序中定义，非临时开辟，不能用完后释放
    struct Student_l a,b,c,*head,*p; //a,b,c作为链表结点
    a.num = 1; a.score = 89.5;
    b.num = 3; b.score = 90;
    c.num = 7; c.score = 85;
    head = &a; //将结点a的起始地址作为头指针head
    a.next = &b; //将结点b起始地址赋值给a.next成员
    b.next = &c; //将结点c起始地址赋值给b.next成员
    c.next = NULL; //c结点的next为链尾
    p = head; //使得p指向a结点
    do {
        printf("%ld %f\n",p->num,p->score);//输出p指向的每个节点的数据
        p=p->next; //使得p指向下一个结点
    }while(p!=NULL);

    struct LinkNode
    {
        int data;
        struct LinkNode *next;
    };
    struct LinkNode node1 = {10,NULL};
    struct LinkNode node2 = {20,NULL};
    struct LinkNode node3 = {30,NULL};
    struct LinkNode node4 = {40,NULL};
    struct LinkNode node5 = {50,NULL};
    node1.next = &node2;
    node2.next = &node3;
    node3.next = &node4;
    node4.next = &node5;
    //如何遍历链表？
    struct LinkNode *pCurrent = &node1; //定义一个辅助指针变量
    while(pCurrent != NULL)
    {
        printf("%d",pCurrent->data);
        //指针后移到下一个元素的首地址
        pCurrent = pCurrent->next;
    }

    //9.4.3 建立动态链表
    /* 建立动态链表：程序执行过程中，从无到有地建立起一个链表
     * 即一个个地开辟结点和输入各结点数据，并建立前后相链的关系
     * */

    //例1:
    //见上诉类外函数

    //例2：写一个3名学生数据的单向动态链表
    //使用 malloc() calloc() realloc() free()
    /*
     * 算法实现：
     * 定义三个指针变量，head，p1和p2，用来指向struct Student
     * 先用malloc函数开辟第一个结点，使p1和p2指向它,从键盘读取一个学生数据，赋予p1指向的第一个结点
     * 先使得head为NULL(0)，表示链表为空，当建立第一个结点时，head指向该结点
     * 若p->num不等于0，则输入的第一个结点数据(n=1)，令head=p1，即把p1的值
     * 赋给head，也就是使head也指向新开辟的结点，然后再开辟另一个结点使得p1指向它,接着输入该结点的值
     * */
    //见类外函数

    system("pause");
    return;
}

void CppDemo::pointer_demo()
{

}

void CppDemo::union_demo()
{
    /*
     * 用同一段内存单元存放不同类型的变量,使几个不同的变量共享同一段内存的结构
     * union 共用体名
     {  成员列表名
     } 变量表列

     * 几个变量共用同一个内存区
     * */
    //共用体变量所占的内存长度等于最长的成员的长度
    union Data //声明共用体类型
    {
        int i;
        char ch;
        float f;
    }a,b,c;
    union Data d,e,f;//声明共用体类型定义变量

    /*
     * 注意：
     * 一、同一内存段在每一个瞬时内只能存放其中一个成员
     * 二、可以对共用体初始化，但初始化列表中只能有一个常量
     * 三、共用体变量中起作用的成员是最后一次被赋值的成员
     * 四、共用体变量的地址和它各成员的地址相同
     * 五、不能对共用体变量名赋值，也不能企图引用其得到一个值
     * */
}

void CppDemo::enum_demo()
{
    /*
     * 枚举：把可能的值一一列举，变量的值只限于列举出来的值的范围内
     * */
    enum Weekday{sun,mon,tue,wed,thu,fri,sat}; //花括号中为枚举元素/常量
    //用此类型来定义变量
    enum Weekday workday,weekend; //枚举类型 + 枚举变量
    workday = mon;
    weekend = sun;
    //workday = monday; 错误，monday不是指定的枚举常量之一
    enum {sun_,mon_,tue_,wed_,thu_,fri_,sat_}workday_,weekend_;
    //enum [枚举名]{枚举元素列表};
    /*
     * 1、枚举元素都按常量处理
     * 2、每一个枚举元素都代表一个整数，默认0，1，2，3，4，5...
     * 3、枚举元素可以用来判断比较
     * */

}

void CppDemo::typedef_demo()
{
    /*
     * typedef指定新的类型名来代替已有的类型名
     * 1、简单用一个新类型名代替原有类型名
     * 2、命名一个简单的类型名代替复杂的类型表示方法
     * */
}

void CppDemo::document_demo()
{

}
